package jmine.tec.web.wicket.component.paging;

import java.util.Iterator;
import java.util.List;

import jmine.tec.web.wicket.BeanReference;

import org.apache.wicket.markup.html.navigation.paging.IPageable;
import org.apache.wicket.markup.repeater.data.IDataProvider;

import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.persist.hibernate.page.PagingData;
import bancosys.tec.persist.hibernate.page.PagingService;

/**
 * @author takeshi
 * @param <T>
 */
public abstract class DAOQueryDataProvider<T> implements IDataProvider<T> {

    private PagingData pagingData = new PagingData();

    private final BeanReference<BaseDAOFactory> daoReference;

    private final BeanReference<PagingService> pagingServiceReference;

    private volatile List<T> queryResult;
    
    private IPageable pageable;
    
    /**
     * @param pageSize int
     * @param daoFactoryReference the {@link BaseDAOFactory} reference
     * @param pagingServiceReference the {@link PagingService} reference
     */
    public DAOQueryDataProvider(int pageSize, BeanReference<BaseDAOFactory> daoFactoryReference,
            BeanReference<PagingService> pagingServiceReference) {
        super();
        this.pagingData.setItensPerPage(pageSize);
        this.daoReference = daoFactoryReference;
        this.pagingServiceReference = pagingServiceReference;
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.apache.wicket.markup.repeater.data.IDataProvider#iterator(int, int)
     */
    public final Iterator<? extends T> iterator(int first, int count) {
        if(this.queryResult == null) {
            this.pagingData.setCurrentPage(first / this.pagingData.getItensPerPage());
            PagingService serv = this.installPagingData();
            try {
                this.queryResult = this.makeQuery(getBaseDAOFactory());
            } finally {
                serv.clearPagingData();
            }
        }
        return queryResult.iterator();
    }
    
    

    /**
     * @param daoFactory {@link BaseDAOFactory}
     * @return {@link List} de T
     */
    protected abstract List<T> makeQuery(BaseDAOFactory daoFactory);

    /**
     * {@inheritDoc}
     */
    public final int size() {
        if(!this.pagingData.isDataInitialized()) {
            this.pagingData.setIncomplete(true);
        }
        if (this.pagingData.isIncomplete()) {
            // install the paging data
            PagingService service = this.installPagingData();
            try {
                this.makeQuery(getBaseDAOFactory());
            } finally {
                service.clearPagingData();
            }
        }
        if(this.pagingData.getTotalItens() >= Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        }
        return (int) this.pagingData.getTotalItens();
    }

    /**
     * @return {@link PagingService}
     */
    private PagingService installPagingData() {
        if (this.pagingServiceReference.get().getPagingData() == null) {
            this.pagingServiceReference.get().setPagingData(this.pagingData);
        } else {
            this.pagingData = this.pagingServiceReference.get().getPagingData();
        }
        return this.pagingServiceReference.get();
    }

    /**
     * {@inheritDoc}
     */
    public void detach() {
        this.queryResult = null;
    }

    /**
     * @return the baseDAOFactory
     */
    public BaseDAOFactory getBaseDAOFactory() {
        return this.daoReference.get();
    }

    /**
     * @return the pageable
     */
    public IPageable getPageable() {
        return pageable;
    }

    /**
     * @param pageable the pageable to set
     */
    public void setPageable(IPageable pageable) {
        this.pageable = pageable;
    }

}
